package examtest;

import java.io.IOException;
import java.util.concurrent.locks.*;

public class homework2 {
    //ReentrantLock测试，相对于synchronize来说的方便之处
    public static void main(String[] args) throws IOException {
        //中断锁测试，回车中断
//        interrupt();

        //公平锁测试，回车查看顺序
//        fairloc();

        //多条件测试，如果是synchoronize则使用notify()和wait(),感觉没有ReentrantLock灵活
//        multiCondition();

        //读写锁
        // 读的过程中别的线程也可以读，不能写
//        readloc();
        // 写的过程中别的线程，不能读，不能写
        writeloc();
//测试完毕
    }

    //1 ReentrantLock可中断
    static void interrupt() throws IOException {
        ReentrantLock lock1=new ReentrantLock();
        ReentrantLock lock2=new ReentrantLock();

        Runnable t1=new MyThread(lock1,lock2);
        Runnable t2=new MyThread(lock2,lock1);
        Thread aa=new Thread(t1,"AA");
        Thread bb=new Thread(t2,"BB");
        aa.start();
        bb.start();


    }

    //2 ReentrantLock公平锁
    static void fairloc() throws IOException {
        //创建一个公平锁
        ReentrantLock lock=new ReentrantLock(true);
        //第一个线程可以sleep久一点
        Thread aa=new Thread(new MyThreadfair(lock,100000),"AA");
        aa.start();
        //睡一会打断，看看哪一个先得到锁
        System.in.read();
        aa.interrupt();
        System.out.println(Thread.currentThread().getName() + "中断" + aa.getName());
        //其他先睡再锁，根据醒来时间顺序获得锁
        new Thread(new MyThreadfair22(lock,800),"BB").start();
        new Thread(new MyThreadfair22(lock,20),"CC").start();
        new Thread(new MyThreadfair22(lock,1600),"DD").start();
    }

    //3 多条件
    static void multiCondition() throws IOException {
        //创建锁
        ReentrantLock lock=new ReentrantLock();
        final Condition notFull  = lock.newCondition();//写线程条件
        final Condition notEmpty = lock.newCondition();//读线程条件
        ItemsClass itemsClass=new ItemsClass(0);

        Thread aa=new Thread(new MyThreadPlus(lock,itemsClass,notFull,notEmpty),"读");
        Thread bb=new Thread(new MyThreadMinus(lock,itemsClass,notFull,notEmpty),"写");
        aa.start();
        bb.start();
    }

    //4 读写锁,先加读锁
    static void readloc() throws IOException {
        //操作对象
        ItemsClass itemsClass=new ItemsClass(0);
        //创建锁
        ReadWriteLock lock = new ReentrantReadWriteLock();

        Thread aa=new Thread(new MyThreadRead(lock,itemsClass),"读线程aa");
        Thread bb=new Thread(new MyThreadRead(lock,itemsClass),"读线程bb");
        Thread dd=new Thread(new MyThreadRead(lock,itemsClass),"读线程dd");
        Thread ee=new Thread(new MyThreadRead(lock,itemsClass),"读线程ee");
        Thread AA=new Thread(new MyThreadWrite(lock,itemsClass),"写线程AA");
        aa.start();
        bb.start();
        dd.start();
        ee.start();
        AA.start();
    }
    //先加写锁
    static void writeloc() throws IOException {
        //操作对象
        ItemsClass itemsClass=new ItemsClass(0);
        //创建锁
        ReadWriteLock lock = new ReentrantReadWriteLock();

        Thread AA=new Thread(new MyThreadWrite(lock,itemsClass),"写线程AA");
        Thread BB=new Thread(new MyThreadWrite(lock,itemsClass),"写线程BB");
        Thread CC=new Thread(new MyThreadWrite(lock,itemsClass),"写线程CC");
        Thread DD=new Thread(new MyThreadWrite(lock,itemsClass),"写线程DD");
        Thread aa=new Thread(new MyThreadRead(lock,itemsClass),"读线程aa");
        Thread bb=new Thread(new MyThreadRead(lock,itemsClass),"读线程bb");
        Thread dd=new Thread(new MyThreadRead(lock,itemsClass),"读线程dd");
        Thread ee=new Thread(new MyThreadRead(lock,itemsClass),"读线程ee");

        for (int i = 0; i <10 ; i++) {
            AA.start();
        }
        BB.start();
        CC.start();
        DD.start();
        aa.start();
        bb.start();
        dd.start();
        ee.start();
    }
}

//1.死锁+中断锁测试class,先锁再睡
class MyThread implements Runnable {
    private Lock lock1=null;
    private Lock lock2=null;
    Integer testNum;

    MyThread(ReentrantLock reentrantLock1,ReentrantLock reentrantLock2){
        this.lock1=reentrantLock1;
        this.lock2=reentrantLock2;
    }

    public void run() {
        lock1.lock();
        try{
            for(int i=0;i<10;i++){
                System.out.println(Thread.currentThread().getName()+":"+i);

                //睡眠来达成死锁条件
                Thread.sleep(300);

                lock2.lockInterruptibly();
                System.out.println(Thread.currentThread().getName()+"获取第二个锁");

            }
        }catch (Exception e){
            e.printStackTrace();
        }
        finally{
            //需要手动unlock
            lock1.unlock();
            lock2.unlock();
        }
    }

}

//2.1公平锁测试class
class MyThreadfair implements Runnable {
    static Lock lock=null;
    Integer sleepNum;


    MyThreadfair(ReentrantLock reentrantLock,Integer sleepNum){
        this.lock=reentrantLock;
        this.sleepNum=sleepNum;
    }
    public void run() {
        //先锁再睡
        lock.lock();
        try{
            System.out.println(Thread.currentThread().getName()+"---开始睡眠");
            Thread.sleep(sleepNum);
            System.out.println(Thread.currentThread().getName()+"结束");

        }catch (Exception e){
            e.printStackTrace();
        }
        finally{
            //需要手动unlock
            lock.unlock();

        }

    }

}
//2.2公平锁其他等待线程测试class,先睡再锁
class MyThreadfair22 implements Runnable {
    private Lock lock = null;
    Integer sleepNum;

    MyThreadfair22(ReentrantLock reentrantLock, Integer sleepNum) {
        this.lock = reentrantLock;
        this.sleepNum = sleepNum;
    }

    public void run() {

        try {
//            System.out.println(Thread.currentThread().getName() + "---开始睡眠");
            //先睡再锁
            Thread.sleep(sleepNum);
            lock.lock();
            System.out.println(Thread.currentThread().getName() + "获得了锁");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //需要手动unlock
            lock.unlock();
        }
    }
}

//3 多个condition，消费者生产者
//操作对象
class ItemsClass{
    static Integer items;
    ItemsClass(Integer items){
        this.items=items;
    }
//
//    public static Integer getItems() {
//        return items;
//    }
//
//    public static void setItems(Integer items) {
//        ItemsClass.items = items;
//    }
}
//生产者
class MyThreadPlus implements Runnable{
    Lock lock;
    ItemsClass itemsClass;
    Condition notFull;
    Condition notEmpty;

    MyThreadPlus(ReentrantLock lock,ItemsClass itemsClass,Condition notFull,Condition notEmpty){
        this.lock=lock;
        this.itemsClass=itemsClass;
        this.notFull=notFull;
        this.notEmpty=notEmpty;
    }

    @Override
    public void run() {
        while (itemsClass.items<= 100){
            lock.lock();
            try {
                while (itemsClass.items>= 100){
                    notFull.await();
                }
                itemsClass.items++;
                System.out.println("正在写入，当前值为"+itemsClass.items);
                notEmpty.signal();
            }catch (Exception e){
                e.printStackTrace();
            }
            finally {
                lock.unlock();
            }
        }
    }
}
//消费者
class MyThreadMinus implements Runnable{
    Lock lock;
    ItemsClass itemsClass;
    Condition notFull;
    Condition notEmpty;

    MyThreadMinus(ReentrantLock lock,ItemsClass itemsClass,Condition notFull,Condition notEmpty){
        this.lock=lock;
        this.itemsClass=itemsClass;
        this.notFull=notFull;
        this.notEmpty=notEmpty;
    }

    @Override
    public void run() {
        while (itemsClass.items>=0){
            lock.lock();
            try {
                while (itemsClass.items<=0){
                    notEmpty.await();
                }
                itemsClass.items--;
                System.out.println("正在读出，当前值为"+itemsClass.items);
                notFull.signal();
            }catch (Exception e){
                e.printStackTrace();
            }
            finally {
                lock.unlock();
            }
        }
    }
}


//4 读写锁
class MyThreadRead implements Runnable{
    ReadWriteLock lock;
    ItemsClass itemsClass;

    MyThreadRead(ReadWriteLock lock,ItemsClass itemsClass){
        this.lock=lock;
        this.itemsClass=itemsClass;
    }

    @Override
    public void run() {
            lock.readLock().lock();
            try {
                while (true) {
                    System.out.println(Thread.currentThread().getName()+"正在读，当前值为" + itemsClass.items);
                    Thread.sleep(100);
                }
            }catch (Exception e){
                e.printStackTrace();
            }
            finally {
                lock.readLock().unlock();
            }
    }
}
class MyThreadWrite implements Runnable{
    ReadWriteLock lock;
    ItemsClass itemsClass;

    MyThreadWrite(ReadWriteLock lock,ItemsClass itemsClass){
        this.lock=lock;
        this.itemsClass=itemsClass;
    }

    @Override
    public void run() {
        lock.writeLock().lock();
        try {
            while (itemsClass.items<=100) {
                itemsClass.items++;
                System.out.println(Thread.currentThread().getName()+"正在写，当前值为" + itemsClass.items);
                Thread.sleep(100);
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        finally {
            lock.writeLock().unlock();
        }
    }
}
